/*******************************************************************************************
Copyright (C) 2017 Mestrelab Research S.L. All rights reserved.

This file is part of the Mnova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/

/*globals mainWindow, nmr, serialization, settings, Application, Dir, File, FileDialog, MnUi, NMRSpectrum, ProgressDialog, Str, BinaryStream*/
/*jslint plusplus: true, indent: 4, nomen: true*/

function importSpinachJson() {
	"use strict";

	var fi, fileName, fin, sin, dat, dims, hyper, ni, np,
		i, j, spectrum, proc, spins, frequency = [], startPPM = [], endPPM = [], offset, sweep, realValues, imgValues, progressBar,
		dirSetKey = "importSpinachJson/Dir", auxFileName,
		openDir = settings.value(dirSetKey, Dir.home()), size1D,
		fileNames = FileDialog.getOpenFileNames("Spinach JSON (*.json)", "", openDir);

	if (!fileNames.length) {
		return;
	}

	//Create a progress bar in order to inform to the user about the state of the import process
	progressBar = new ProgressDialog();
	progressBar.minimum = 0;
	progressBar.maximum = 100;
	progressBar.value = 0;
	progressBar.visible = true;

	serialization.fileHistory = false;
	for (fi = 0; fi < fileNames.length; fi++) {
		fileName = fileNames[fi];
		fin = new File(fileName);

		//Update progress bar
		auxFileName = fileName.substring(fileName.lastIndexOf("/") + 1, fileName.length);
		progressBar.labelText = "Importing " + auxFileName + " file";
		progressBar.value = 0;
		progressBar.update();

		if (!fi) {
			settings.setValue(dirSetKey, fin.absDirPath);
		}

		fin.open(File.ReadOnly);
		sin = new BinaryStream(fin);
		progressBar.value = 25;
		progressBar.update();
		dat = JSON.parse(sin.readBytes(fin.size).toString());
		progressBar.value = 50;
		progressBar.update();
		fin.close();

		if (typeof dat.spinach === 'object') { //simple data validation
			dims = dat.spinach.parameters.npoints.length;
			if (dims < 0 || dims > 2) {
				return;
			}

			spins = importSpinachJson.dimArray(dat.spinach.parameters.spins, dims);
			frequency.push(importSpinachJson.magnetToFreq(dat.spinach.sys.magnet, spins[0]));
			if (dims > 1) {
				frequency.push(importSpinachJson.magnetToFreq(dat.spinach.sys.magnet, spins[1]));
			}
			offset = importSpinachJson.dimArray(dat.spinach.parameters.offset, dims);
			sweep = importSpinachJson.dimArray(dat.spinach.parameters.sweep, dims);

			startPPM.push((offset[0] - sweep[0] / 2.0) / frequency[0]);
			endPPM.push((offset[0] + sweep[0] / 2.0) / frequency[0]);
			if (dims > 1) {
				startPPM.push((offset[1] - sweep[1] / 2.0) / frequency[1]);
				endPPM.push((offset[1] + sweep[1] / 2.0) / frequency[1]);
			}

			if (dims === 2 && dat.spinach.fid.cos !== undefined && dat.spinach.fid.sin !== undefined) {
				hyper = 2;
			} else {
				hyper = 1;
			}

			if (dims === 2) {
				spectrum = new NMRSpectrum({
					1: {nucleus: dat.spinach.parameters.spins[1],
						frequency: frequency[1],
						from_ppm: startPPM[1],
						to_ppm: endPPM[1],
						size: dat.spinach.parameters.npoints[1] * hyper},
					2: {nucleus: dat.spinach.parameters.spins[0],
						frequency: frequency[0],
						from_ppm: startPPM[0],
						to_ppm: endPPM[0],
						size: dat.spinach.parameters.npoints[0]},
					filename: fileName,
					origin: 'Spinach JSON',
					title: ''
				});
			} else {
				if (Array.isArray(dat.spinach.parameters.npoints)) {
					size1D = dat.spinach.parameters.npoints[0];
				} else {
					size1D = parseInt(dat.spinach.parameters.npoints);
				}
				if (isNaN(size1D)) {
					throw "Invalid size %1".format(size1D);
				}
				spectrum = new NMRSpectrum({
					1: {nucleus: dat.spinach.parameters.spins[0],
						frequency: frequency[0],
						from_ppm: startPPM[0],
						to_ppm: endPPM[0],
						size: size1D
						},
					filename: fileName,
					origin: 'Spinach JSON',
					title: ''
				});
			}

			if (spectrum === undefined || spectrum.isValid() === false) {
				throw "Invalid Spectrum";
			}
			if (dims === 2 && hyper === 2) {
				ni = dat.spinach.fid.cos._ArraySize_[1];
				np = dat.spinach.fid.cos._ArraySize_[0];
			} else if (dims === 2 && hyper === 1) {
				ni = dat.spinach.fid._ArraySize_[1];
				np = dat.spinach.fid._ArraySize_[0];
			} else {
				ni = 0;
				np = dat.spinach.fid._ArraySize_[0];
			}

			if (spectrum !== undefined) {
				nmr.beginFidModification(spectrum);
				//Get the spectrum data in time domain
				if (dims === 2) {
					for (i = 0; i < ni && !progressBar.wasCanceled; i++) { //for each column
						realValues = [];
						imgValues = [];
						for (j = 0; j < np; j++) { //for each point
							if (hyper === 2) {
								realValues.push(dat.spinach.fid.cos._ArrayData_[j + i * np][0]);
								imgValues.push(dat.spinach.fid.cos._ArrayData_[j + i * np][1]);
							} else {
								realValues.push(dat.spinach.fid._ArrayData_[j + i * np][0]);
								imgValues.push(dat.spinach.fid._ArrayData_[j + i * np][1]);
							}
						}
						spectrum.fidSetReal(i * hyper, "all", realValues);
						spectrum.fidSetImag(i * hyper, "all", imgValues);
						if (hyper === 2) {
							realValues = [];
							imgValues = [];
							for (j = 0; j < np; j++) { //for each point, cos
								realValues.push(dat.spinach.fid.sin._ArrayData_[j + i * np][0]);
								imgValues.push(dat.spinach.fid.sin._ArrayData_[j + i * np][1]);
							}
							spectrum.fidSetReal(i * hyper + 1, "all", realValues);
							spectrum.fidSetImag(i * hyper + 1, "all", imgValues);
						}
						progressBar.value = 50.0 + i / ni * 50.0;
						progressBar.update();
					}
				} else {
					realValues = [];
					imgValues = [];
					for (j = 0; j < np; j++) { //for each point, cos
						realValues.push(dat.spinach.fid._ArrayData_[j][0]);
						imgValues.push(dat.spinach.fid._ArrayData_[j][1]);
					}
					spectrum.fidSetReal("all", realValues);
					spectrum.fidSetImag("all", imgValues);
					progressBar.value = 100.0;
					progressBar.update();
				}
				nmr.endFidModification(spectrum);
				if (spectrum.isValid()) {
				//Deal with the processing parameters
					proc = spectrum.proc;
					proc.setParameter("FT[1].Quadrature", true);
					if (dims === 2) {
						proc.setParameter("FT[2].Quadrature", true);
						if (hyper === 2) {
							proc.setParameter("FT[1].Hyper", true);
							proc.setParameter("FT[1].Protocol", "Hyper");
							proc.setParameter("FT[1].Invert", true);
						} else {
							proc.setParameter("PC[2].Method", "Magnitude");
						}
						if (dat.spinach.parameters.zerofill[0] > 0) {
							proc.setParameter("ZF[2].size", dat.spinach.parameters.zerofill[0]);
						}
						if (dat.spinach.parameters.zerofill[0] > 0) {
							proc.setParameter("ZF[1].size", dat.spinach.parameters.zerofill[1]);
						}
					} else {
						if (dat.spinach.parameters.zerofill[0] > 0) {
							proc.setParameter("ZF[1].size", dat.spinach.parameters.zerofill[0]);
						}
					}
					//release memory
					dat = null;
					spectrum.process(proc);
					//spectrum.threshold = spectrum.realMax * 0.01;
					spectrum.fitToHeight();
					spectrum.update();
				}
			}
		}
	}

	//Update current document
	if (Application.mainWindow.activeDocument !== undefined) {
		Application.mainWindow.activeDocument.update();
	}

	//Finalize progress bar and history
	serialization.fileHistory = true;
	progressBar.value = 100;
	progressBar.visible = false;
}

importSpinachJson.nmrTable = [
	{ "Nucleus": "1H", "Freq": 750.03 },
	{ "Nucleus": "2H", "Freq": 115.13 },
	{ "Nucleus": "3He", "Freq": 800.01 },
	{ "Nucleus": "6Li", "Freq": 110.38 },
	{ "Nucleus": "7Li", "Freq": 291.51 },
	{ "Nucleus": "9Be", "Freq": 105.41 },
	{ "Nucleus": "11B", "Freq": 240.68 },
	{ "Nucleus": "10B", "Freq": 80.6 },
	{ "Nucleus": "13C", "Freq": 188.64 },
	{ "Nucleus": "14N", "Freq": 54.22 },
	{ "Nucleus": "15N", "Freq": 76.05 },
	{ "Nucleus": "17O", "Freq": 101.72 },
	{ "Nucleus": "19F", "Freq": 705.99 },
	{ "Nucleus": "21Ne", "Freq": 59.24 },
	{ "Nucleus": "23Na", "Freq": 198.51 },
	{ "Nucleus": "25Mg", "Freq": 45.95 },
	{ "Nucleus": "27Al", "Freq": 195.59 },
	{ "Nucleus": "29Si", "Freq": 149.13 },
	{ "Nucleus": "31P", "Freq": 303.9 },
	{ "Nucleus": "33S", "Freq": 57.62 },
	{ "Nucleus": "35Cl", "Freq": 73.57 },
	{ "Nucleus": "37Cl", "Freq": 61.24 },
	{ "Nucleus": "41K", "Freq": 0 },
	{ "Nucleus": "39K", "Freq": 35.05 },
	{ "Nucleus": "43Ca", "Freq": 50.54 },
	{ "Nucleus": "45Sc", "Freq": 182.49 },
	{ "Nucleus": "47Ti", "Freq": 42.35 },
	{ "Nucleus": "49Ti", "Freq": 42.36 },
	{ "Nucleus": "51V", "Freq": 197.17 },
	{ "Nucleus": "50V", "Freq": 74.74 },
	{ "Nucleus": "53Cr", "Freq": 42.26 },
	{ "Nucleus": "55Mn", "Freq": 185.56 },
	{ "Nucleus": "57Fe", "Freq": 24.25 },
	{ "Nucleus": "59Co", "Freq": 176.98 },
	{ "Nucleus": "61Ni", "Freq": 67.14 },
	{ "Nucleus": "65Cu", "Freq": 213.23 },
	{ "Nucleus": "63Cu", "Freq": 199.27 },
	{ "Nucleus": "67Zn", "Freq": 125.5 },
	{ "Nucleus": "71Ga", "Freq": 229.37 },
	{ "Nucleus": "69Ga", "Freq": 180.52 },
	{ "Nucleus": "73Ge", "Freq": 26.24 },
	{ "Nucleus": "75As", "Freq": 128.86 },
	{ "Nucleus": "77Se", "Freq": 143.58 },
	{ "Nucleus": "79Br", "Freq": 188.56 },
	{ "Nucleus": "81Br", "Freq": 203.26 },
	{ "Nucleus": "83Kr", "Freq": 28.96 },
	{ "Nucleus": "87Rb", "Freq": 245.4 },
	{ "Nucleus": "85Rb", "Freq": 72.41 },
	{ "Nucleus": "87Sr", "Freq": 32.62 },
	{ "Nucleus": "89Y", "Freq": 36.74 },
	{ "Nucleus": "91Zr", "Freq": 70.02 },
	{ "Nucleus": "93Nb", "Freq": 184.12 },
	{ "Nucleus": "97Mo", "Freq": 50.14 },
	{ "Nucleus": "95Mo", "Freq": 49.09 },
	{ "Nucleus": "99Ru", "Freq": 33.43 },
	{ "Nucleus": "101Ru", "Freq": 37.46 },
	{ "Nucleus": "103Rh", "Freq": 23.74 },
	{ "Nucleus": "105Pd", "Freq": 34.37 },
	{ "Nucleus": "107Ag", "Freq": 30.51 },
	{ "Nucleus": "109Ag", "Freq": 35.15 },
	{ "Nucleus": "111Cd", "Freq": 159.85 },
	{ "Nucleus": "113Cd", "Freq": 167.23 },
	{ "Nucleus": "113In", "Freq": 164.98 },
	{ "Nucleus": "115In", "Freq": 165.33 },
	{ "Nucleus": "117Sn", "Freq": 268.83 },
	{ "Nucleus": "119Sn", "Freq": 281.25 },
	{ "Nucleus": "115Sn", "Freq": 246.76 },
	{ "Nucleus": "121Sb", "Freq": 180.67 },
	{ "Nucleus": "123Sb", "Freq": 97.86 },
	{ "Nucleus": "123Te", "Freq": 197.87 },
	{ "Nucleus": "125Te", "Freq": 238.56 },
	{ "Nucleus": "127I", "Freq": 151.1 },
	{ "Nucleus": "131Xe", "Freq": 61.93 },
	{ "Nucleus": "129Xe", "Freq": 208.93 },
	{ "Nucleus": "133Cs", "Freq": 99.08 },
	{ "Nucleus": "135Ba", "Freq": 75.04 },
	{ "Nucleus": "137Ba", "Freq": 83.94 },
	{ "Nucleus": "139La", "Freq": 106.78 },
	{ "Nucleus": "138La", "Freq": 99.74 },
	{ "Nucleus": "141Pr", "Freq": 214.84 },
	{ "Nucleus": "143Nd", "Freq": 41.3 },
	{ "Nucleus": "145Nd", "Freq": 25.51 },
	{ "Nucleus": "147Sm", "Freq": 31.18 },
	{ "Nucleus": "149Sm", "Freq": 25.71 },
	{ "Nucleus": "153Eu", "Freq": 82.37 },
	{ "Nucleus": "151Eu", "Freq": 186.51 },
	{ "Nucleus": "157Gd", "Freq": 30.25 },
	{ "Nucleus": "155Gd", "Freq": 23.14 },
	{ "Nucleus": "159Tb", "Freq": 180.2 },
	{ "Nucleus": "161Dy", "Freq": 25.38 },
	{ "Nucleus": "163Dy", "Freq": 35.72 },
	{ "Nucleus": "165Ho", "Freq": 160.06 },
	{ "Nucleus": "167Er", "Freq": 21.73 },
	{ "Nucleus": "169Tm", "Freq": 62.57 },
	{ "Nucleus": "173Yb", "Freq": 36.52 },
	{ "Nucleus": "171Yb", "Freq": 132.73 },
	{ "Nucleus": "175Lu", "Freq": 85.86 },
	{ "Nucleus": "179Hf", "Freq": 19.12 },
	{ "Nucleus": "181Ta", "Freq": 90.94 },
	{ "Nucleus": "183W", "Freq": 31.63 },
	{ "Nucleus": "187Re", "Freq": 172.92 },
	{ "Nucleus": "185Re", "Freq": 171.18 },
	{ "Nucleus": "187Os", "Freq": 17.6 },
	{ "Nucleus": "189Os", "Freq": 65.53 },
	{ "Nucleus": "191Ir", "Freq": 13.02 },
	{ "Nucleus": "193Ir", "Freq": 14.37 },
	{ "Nucleus": "195Pt", "Freq": 163.68 },
	{ "Nucleus": "197Au", "Freq": 13.15 },
	{ "Nucleus": "201Hg", "Freq": 50.15 },
	{ "Nucleus": "199Hg", "Freq": 135.86 },
	{ "Nucleus": "205Tl", "Freq": 439.81 },
	{ "Nucleus": "203Tl", "Freq": 435.66 },
	{ "Nucleus": "207Pb", "Freq": 157.75 },
	{ "Nucleus": "177Hf", "Freq": 30.44 },
	{ "Nucleus": "209Bi", "Freq": 125.95 },
	{ "Nucleus": "229Th", "Freq": 21.48 },
	{ "Nucleus": "235U", "Freq": 13.43 }
];

importSpinachJson.magnetToFreq = function (aField, aSpin) {
	"use strict";
	var i;
	for (i = 0; i < importSpinachJson.nmrTable.length; i++) {
		if (importSpinachJson.nmrTable[i].Nucleus === aSpin.toString()) {
			return importSpinachJson.nmrTable[i].Freq / 750.03 * aField * 42.5781;
		}
	}
	return 400.0;
};

importSpinachJson.dimArray = function (aPar, aDims) {
	"use strict";
	var arr = [];
	if (aPar[0] !== undefined) {
		arr.push(aPar[0]);
		if (aDims > 1) {
			if (aPar[1] !== undefined) {
				arr.push(aPar[1]);
			} else {
				arr.push(aPar[0]);
			}
		}
	} else {
		arr.push(aPar);
		if (aDims > 1) {
			arr.push(aPar);
		}
	}
	return arr;
};

if (this.MnUi && MnUi.scripts_nmr) {
	MnUi.scripts_nmr.scripts_nmr_ImportSpinachJson = importSpinachJson;
}
